package indi.jp.project.process.service.impl;

import indi.jp.project.center.entity.Task;
import indi.jp.project.center.service.TaskService;
import indi.jp.project.core.entity.JsonResult;
import indi.jp.project.core.util.SerialUtil;
import indi.jp.project.process.dao.FlowTaskDAO;
import indi.jp.project.process.entity.*;
import indi.jp.project.process.service.FlowTaskNotifyService;
import indi.jp.project.process.service.FlowTaskService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * 任务流程实现
 *
 * @author jiangping
 * @date 2022/5/5
 */
@Service
public class FlowTaskServiceImpl implements FlowTaskService {

    @Resource
    private FlowTaskDAO flowTaskDAO;

    @Resource
    private SerialUtil serialUtil;

    @Resource
    private TaskService taskService;

    @Resource
    Map<String, FlowTaskNotifyService> serviceMap;

    @Override
    public JsonResult queryTaskFlow(String taskId) throws Exception {
        LinkedList<FlowTask> list = flowTaskDAO.queryTaskFlow(taskId);
        return JsonResult.success(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTaskFlow(String taskId, List<FlowTask> list) throws Exception {
        if (list != null && list.size() > 0) {
            flowTaskDAO.deleteTaskFlow(taskId);
            list.forEach(flowTask -> {
                flowTask.setId(String.valueOf(serialUtil.nextId()));
                flowTask.setTaskId(taskId);
            });
            flowTaskDAO.saveTaskFlow(list);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult flowSubmit(FlowTaskParam flowTaskParam) throws Exception {
        // 根据流程类型确定操作的表
        String typeCode = flowTaskParam.getFlowTypeCode();
        String tableName = FlowTypeEnum.valueOf(typeCode).getTableName();
        // 获取任务流程信息
        FlowTaskInfo flowTaskInfo = flowTaskDAO.queryTaskInfo(tableName, flowTaskParam.getTaskId());
        if (flowTaskInfo.getState() != flowTaskParam.getState()) {
            return JsonResult.failure("任务状态已改变，请刷新后重试");
        }

        // 获取当前和下一步流程
        FlowTaskStep flowTaskStep = getFlowStep(flowTaskInfo.getState(), flowTaskInfo.getRejectedState(),
                flowTaskParam.getTaskId(), flowTaskParam.getOperation());


        // 创建用于更新任务表流程的实体
        FlowTaskParam taskFlowEntity = new FlowTaskParam();
        BeanUtils.copyProperties(flowTaskStep.getNextStep(), taskFlowEntity);
        // 如果是提交，则更新任务状态为可撤回，否则为不可驳回
        if ("submit".equals(flowTaskParam.getOperation())) {
            taskFlowEntity.setAllowRevoke(1);
        } else {
            taskFlowEntity.setAllowRevoke(0);
        }
        taskFlowEntity.setTableName(tableName);
        flowTaskDAO.updateTaskFlow(taskFlowEntity);
        // 保存任务操作历史
        FlowTaskHistory flowTaskHistory = new FlowTaskHistory();
        BeanUtils.copyProperties(flowTaskParam, flowTaskHistory);
        BeanUtils.copyProperties(flowTaskStep.getCurrentStep(), flowTaskHistory);
        flowTaskHistory.setId(String.valueOf(serialUtil.nextId()));
        flowTaskHistory.setNodeName(flowTaskStep.getCurrentStep().getName());
        flowTaskDAO.saveOperationHistory(flowTaskHistory);
        // 保存到任务中心
        Task task = new Task();
        task.setId(String.valueOf(serialUtil.nextId()));
        task.setTaskId(flowTaskParam.getTaskId());
        task.setTaskName(FlowTypeEnum.valueOf(typeCode).getFlowName());
        task.setTaskState(flowTaskStep.getNextStep().getState());
        task.setTaskStateName(flowTaskStep.getNextStep().getStateName());
        task.setTaskHandler(flowTaskStep.getNextStep().getHandler());
        task.setTaskHandlerName(flowTaskStep.getNextStep().getHandlerName());
        task.setTaskType(flowTaskInfo.getTaskType());
        task.setTaskCreator(flowTaskInfo.getCreateBy());
        task.setCreateBy(flowTaskParam.getCreateBy());
        taskService.generateTask(task);
        // 如果对应的Service需要通知，则调用通知方法
        FlowTaskNotifyService flowTaskNotifyService = serviceMap.get(FlowTypeEnum.valueOf(typeCode).getServiceName());
        if (flowTaskNotifyService != null) {
            FlowTaskNotifyDTO flowTaskNotifyDTO = new FlowTaskNotifyDTO();
            flowTaskNotifyDTO.setTaskId(flowTaskParam.getTaskId());
            flowTaskNotifyDTO.setOperation(flowTaskParam.getOperation());
            flowTaskNotifyDTO.setCurrentState(flowTaskStep.getCurrentStep().getState());
            flowTaskNotifyDTO.setNextState(flowTaskStep.getNextStep().getState());
            flowTaskNotifyDTO.setFlowType(flowTaskParam.getFlowTypeCode());
            flowTaskNotifyDTO.setHandler(flowTaskParam.getHandler());
            flowTaskNotifyDTO.setHandlerName(flowTaskParam.getHandlerName());
            flowTaskNotifyDTO.setCreateBy(flowTaskParam.getCreateBy());
            flowTaskNotifyService.notify(flowTaskNotifyDTO);
        }
        return JsonResult.success("操作成功");
    }

    @Override
    public JsonResult flowAgree(FlowTaskParam flowTaskParam) throws Exception {
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult flowReject(FlowTaskParam flowTaskParam) throws Exception {
        // 根据流程类型确定操作的表
        String typeCode = flowTaskParam.getFlowTypeCode();
        String tableName = FlowTypeEnum.valueOf(typeCode).getTableName();
        // 获取任务流程信息
        FlowTaskInfo flowTaskInfo = flowTaskDAO.queryTaskInfo(tableName, flowTaskParam.getTaskId());
        if (flowTaskInfo.getState() != flowTaskParam.getState()) {
            return JsonResult.failure("任务状态已改变，请刷新后重试");
        }
        // 获取当前和下一步流程
        FlowTaskStep flowTaskStep = getFlowStep(flowTaskInfo.getState(), flowTaskInfo.getRejectedState(),
                flowTaskParam.getTaskId(), flowTaskParam.getOperation());
        // 创建用于更新任务表流程的实体
        FlowTaskParam taskFlowEntity = new FlowTaskParam();
        taskFlowEntity.setTableName(tableName);
        taskFlowEntity.setTaskId(flowTaskParam.getTaskId());
        // 如果是技术标/商务标，则驳回到负责人节点
        if(FlowTypeEnum.BID_TECH.getFlowType().equals(flowTaskParam.getFlowTypeCode()) || FlowTypeEnum.BID_BUS.getFlowType().equals(flowTaskParam.getFlowTypeCode())){
            taskFlowEntity.setState(1);
        } else {
            taskFlowEntity.setState(0);
        }
        taskFlowEntity.setAllowRevoke(0);
        taskFlowEntity.setRejectedState(flowTaskInfo.getState());
        flowTaskDAO.updateTaskFlow(taskFlowEntity);
        // 保存任务操作历史
        FlowTaskHistory flowTaskHistory = new FlowTaskHistory();
        BeanUtils.copyProperties(flowTaskParam, flowTaskHistory);
        BeanUtils.copyProperties(flowTaskStep.getCurrentStep(), flowTaskHistory);
        flowTaskHistory.setId(String.valueOf(serialUtil.nextId()));
        flowTaskHistory.setNodeName(flowTaskStep.getCurrentStep().getName());
        flowTaskDAO.saveOperationHistory(flowTaskHistory);
        // 结束任务中心任务
        Task task = new Task();
        task.setTaskId(flowTaskParam.getTaskId());
        task.setTaskState(0);
        taskService.generateTask(task);
        return JsonResult.success("操作成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult flowRevoke(FlowTaskParam flowTaskParam) throws Exception {
        String typeCode = flowTaskParam.getFlowTypeCode();
        String tableName = FlowTypeEnum.valueOf(typeCode).getTableName();
        FlowTaskInfo flowTaskInfo = flowTaskDAO.queryTaskInfo(tableName, flowTaskParam.getTaskId());
        if (!flowTaskInfo.isAllowRevoke()) {
            return JsonResult.failure("任务状态已变更，无法撤回，请刷新后查看当前任务状态");
        }
        FlowTaskStep flowTaskStep = getFlowStep(flowTaskInfo.getState(), flowTaskInfo.getRejectedState(),
                flowTaskParam.getTaskId(), flowTaskParam.getOperation());
        FlowTaskParam taskFlowEntity = new FlowTaskParam();
        taskFlowEntity.setTableName(tableName);
        taskFlowEntity.setTaskId(flowTaskParam.getTaskId());
        taskFlowEntity.setState(0);
        taskFlowEntity.setAllowRevoke(0);
        flowTaskDAO.updateTaskFlow(taskFlowEntity);
        // 保存任务操作历史
        FlowTaskHistory flowTaskHistory = new FlowTaskHistory();
        BeanUtils.copyProperties(flowTaskParam, flowTaskHistory);
        BeanUtils.copyProperties(flowTaskStep.getCurrentStep(), flowTaskHistory);
        flowTaskHistory.setId(String.valueOf(serialUtil.nextId()));
        flowTaskHistory.setNodeName(flowTaskStep.getCurrentStep().getName());
        flowTaskHistory.setHandler(flowTaskStep.getCreateStep().getHandler());
        flowTaskHistory.setHandlerName(flowTaskStep.getCreateStep().getHandlerName());
        flowTaskDAO.saveOperationHistory(flowTaskHistory);
        // 结束任务中心任务
        Task task = new Task();
        task.setTaskId(flowTaskParam.getTaskId());
        task.setTaskState(0);
        taskService.generateTask(task);
        return JsonResult.success();
    }

    /**
     * 获取任务流程
     *
     * @param currentState  当前状态
     * @param rejectedState 任务被驳回时状态
     * @param taskId        任务ID
     * @param operation     操作
     */
    private FlowTaskStep getFlowStep(int currentState, int rejectedState, String taskId, String operation) throws SQLException {
        // 查询任务流程
        LinkedList<FlowTask> list = flowTaskDAO.queryTaskFlow(taskId);
        FlowTaskStep flowTaskStep = new FlowTaskStep();
        // 是否已获取当前状态，已获取则可以判断下一步状态
        boolean currentAcquired = false;
        for (FlowTask step : list) {
            if (step.getState() == 0) {
                flowTaskStep.setCreateStep(step);
            }
            // 如果状态为99，则下一步直接结束
            if (step.getState() == 99) {
                flowTaskStep.setNextStep(step);
                break;
            }
            // 状态相等则给当前状态赋值，并标记已获取当前状态
            if (step.getState() == currentState) {
                flowTaskStep.setCurrentStep(step);
                // 如果是驳回或撤回，则获取当前流程后直接结束循环
                if ("revoke".equals(operation) || "reject".equals(operation)) {
                    break;
                }
                currentAcquired = true;
                continue;
            }
            // 如果已获取当前状态，并且被驳回状态不为0，获取后续系统节点，则下一步为需系统处理的节点
//            if (currentAcquired && step.getCategory() == 0 && rejectedState != 0) {
//                flowTaskStep.setNextStep(step);
//                break;
//            }

            // 已获取当前状态，并且操作为提交/发起，被驳回状态为0，则正常获取下一步处理人不为空的节点
            if (currentAcquired
                    && ("submit".equals(operation) || "initiated".equals(operation))
                    && rejectedState == 0
                    && step.getState() != 99
                    && !"".equals(step.getHandler())) {
                flowTaskStep.setNextStep(step);
                break;
            }

            // 已获取当前状态，并且操作为提交，被驳回状态不为0，则下一步为上次被驳回时的节点
            if (currentAcquired
                    && "submit".equals(operation)
                    && rejectedState != 0
                    && rejectedState == step.getState()) {
                flowTaskStep.setNextStep(step);
                break;
            }

            // 如果是同意操作，正常获取下一步
            if (currentAcquired
                    && "agree".equals(operation)
                    && step.getState() != 99
                    && !"".equals(step.getHandler())) {
                flowTaskStep.setNextStep(step);
                break;
            }


        }
        return flowTaskStep;
    }

    @Override
    public JsonResult flowCancel(FlowTaskParam flowTaskParam) throws Exception {
        return JsonResult.success("操作成功");
    }

    @Override
    public JsonResult loadFlowHistory(String taskId) throws Exception {
        List<FlowTaskHistory> list = flowTaskDAO.queryTaskFlowHistory(taskId);
        return JsonResult.success(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteFlowByTaskId(String taskId) throws Exception {
        flowTaskDAO.deleteTaskFlow(taskId);
        flowTaskDAO.deleteFlowHistoryByTaskId(taskId);
        taskService.deleteByTaskId(taskId);
    }

}
